import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as CANNON from 'cannon-es'

const world = new CANNON.World()
world.gravity.set(0, -0.98, 0) // 设置重力
world.allowSleep = true

const GROUP1 = 1
const GROUP2 = 2
const GROUP3 = 4
const GROUP4 = 8

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight)
camera.position.set(0, 3, 5)
scene.add(camera)

const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.shadowMap.enabled = true
renderer.outputColorSpace = THREE.SRGBColorSpace

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true

document.body.appendChild(renderer.domElement)

const axHelp = new THREE.AxesHelper(5)
scene.add(axHelp)


const geometry = new THREE.BoxGeometry(1, 1, 1)

const cube1 = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 'pink' }))
cube1.position.set(-3, 1.5, 0)

const cube2 = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 'green' }))
cube2.position.set(0, 0.5, 0)

const cube3 = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 'mediumpurple' }))
cube3.position.set(3, 0.5, 0)

scene.add(cube1, cube2, cube3)
const meshes = [cube1, cube2, cube3]

const bodyMaterial = new CANNON.Material('boxMaterial')
bodyMaterial.friction = 0.5
bodyMaterial.restitution = 1


const sphereBody1 = new CANNON.Body({
  mass: 1, position: new CANNON.Vec3(-3, 1.5, 0),
  shape: new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)),
  material: bodyMaterial,
  collisionFilterGroup: GROUP1,
  collisionFilterMask: GROUP2 | GROUP3 | GROUP4
})
sphereBody1.allowSleep = true
sphereBody1.sleepSpeedLimit = 0.1 // 速度为 0.1 就允许休眠
sphereBody1.sleepTimeLimit = 1 // 多久之后休眠

// 休眠 和休眠事件
sphereBody1.addEventListener('collide', (event: any) => {
  console.log(event)
})


const sphereBody2 = new CANNON.Body({
  mass: 1, position: new CANNON.Vec3(0, 0.5, 0),
  shape: new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)),
  material: bodyMaterial,
  collisionFilterGroup: GROUP2,
  collisionFilterMask: GROUP1 | GROUP4
})
const sphereBody3 = new CANNON.Body({
  mass: 1, position: new CANNON.Vec3(3, 0.5, 0),
  shape: new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)),
  material: bodyMaterial,
  collisionFilterGroup: GROUP3,
  collisionFilterMask: GROUP1 | GROUP4
})
world.addBody(sphereBody1)
world.addBody(sphereBody2)
world.addBody(sphereBody3)
const bodyMeshes = [sphereBody1, sphereBody2, sphereBody3]


const plane = new THREE.Mesh(
  new THREE.PlaneGeometry(10, 10),
  new THREE.MeshBasicMaterial({ color: 'grey' })
)
plane.rotation.x = -Math.PI / 2
scene.add(plane)

const planeMaterial = new CANNON.Material('ground')
planeMaterial.friction = 0.5
planeMaterial.restitution = 1

const planeBody = new CANNON.Body({
  type: CANNON.Body.STATIC,
  material: planeMaterial,
  collisionFilterGroup: GROUP4,
  collisionFilterMask: GROUP1 | GROUP2 | GROUP3
}).addShape(new CANNON.Plane())
planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2)
world.addBody(planeBody)




const clock = new THREE.Clock()
let preTime = 0


const handleRender = () => {
  const nowTime = clock.getElapsedTime()
  const deltaTime = nowTime - preTime
  preTime = nowTime

  world.step(1 / 60, deltaTime, 3) // 补帧操作
  for(let i = 0; i < meshes.length; i++) {
    meshes[i].position.copy(bodyMeshes[i].position as any)
    meshes[i].quaternion.copy(bodyMeshes[i].quaternion as any)
  }

  controls.update()
  renderer.render(scene, camera)
  window.requestAnimationFrame(handleRender)
}

const handleSize = () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
}

window.addEventListener('resize', handleSize)

handleRender()
